#if !defined(___VIEW_C)
#define ___VIEW_C
#include "std.h"


#include <SDL/SDL.h>
#include <SDL/SDL_ttf.h>


static N1 *_tmp="/tmp/view";
static N1 *_fot="./font/FreeMono.ttf";


typedef struct _tView
{ Str dir,tmp,fot;
} tView;
static tView view;
static N1 *nam1=NULL;

I4 DirList(Str nam,Str **buf,N4 *len);
I4 Load(Str dir,Str *buf,N4 pos,Str tmp,
  SDL_Surface **img,SDL_Surface *scr,TTF_Font *ft);


static Str help=
  "Args: -h| [-l<log>] [-t<tmp>] [-f<font>] [-d<dir>]\n"
  "Defs: -t/tmp/view -f./font/FreeMono.ttf -d.\n";
I4 opts(tProg *prg,tView *view,int argc,char **argv)
{ FILE *f1; N4 i,j; Str s1,p1;
  if (!prg) ERR1("Error: opts: NULL prg",0ul);
  prg->msg=3;
  prg->fi=stdin;
  prg->fo=stdout;
  prg->fb=NULL;

  if (!argc && !argv)
  { fputs(help,prg->fo); return (0); }
  for (++argv,i=1;i<argc;++i)
  { s1=*(argv++);
    if (s1[0]!='-') continue;
    switch (s1[1])
    { case 'h':
        fputs(help,prg->fo);
        exit(0);
      case 'l':
        if (!(f1=fopen(s1+2,"wb")))
          ERR1("Error: Open Output",0l);
        prg->fo=f1;
        break;
      case 't':
        j=StrLen(s1+2);
        if (!(p1=MemGet(j+1)))
          ERR1("Error: Nomem: Tmp",0ul);
        MemCpy(s1+2,p1,j+1);
        view->tmp=p1;
        break;
      case 'f':
        j=StrLen(s1+2);
        if (!(p1=MemGet(j+1)))
          ERR1("Error: Nomem: Fot",0ul);
        MemCpy(s1+2,p1,j+1);
        view->fot=p1;
        break;
      case 'd':
        j=StrLen(s1+2);
        if (!(p1=MemGet(j+1)))
          ERR1("Error: Nomem: Dir",0ul);
        MemCpy(s1+2,p1,j+1);
        if (p1[j-1]=='/' || p1[j-1]=='\\')
          p1[--j]=0; view->dir=p1;
        for (;*p1;++p1) if (*p1=='\\') *p1='/';
        break;
    }
  }
  { N1 buf[500]; struct timeb tmi;
    s1=(view->tmp?view->tmp:_tmp);
    ftime(&tmi); sprintf(buf,"%s.%08lX.bmp",
      s1,tmi.time); i=StrLen(buf);
    if (!(s1=MemGet(i+1)))
      ERR1("Error: Nomem: Tmp",0ul);
    MemCpy(buf,s1,i); s1[i]=0;
    if (view->tmp) MemRel(view->tmp);
    view->tmp=s1;
  }
  if (!view->fot) view->fot=_fot;
  if (!view->dir)
  { if (!(p1=MemGet(2)))
      ERR1("Error: Nomem: Dir",0ul);
    p1[0]='.'; p1[1]=0; view->dir=p1;
  }
  return (0);
}
int main(int argc,char **argv)
{ SDL_Surface *scr,*img;
  SDL_Event evt; SDL_Rect r1;
  Str tmp,dir,*buf; N4 l,k,i,j;
  N1 poll=1,butt=0; Str nam,p1;
  TTF_Font *ft;
  if (opts(prg,&view,argc,argv)==-1l)
    return (-1);

  if (SDL_Init(SDL_INIT_VIDEO)==-1)
    ERR1("Error: SDL: Init",0ul);
  if (TTF_Init())
    ERR1("Error: TTF: Init",0ul);
  if (!(ft=TTF_OpenFont(view.fot,16)))
    ERR1("Error: TTF: Open",0ul);
  //TTF_SetFontStyle(ft,TTF_STYLE_BOLD);
  SDL_WM_SetCaption("View",NULL);
  if (!(scr=SDL_SetVideoMode(640,480,32,
    SDL_SWSURFACE|SDL_RESIZABLE)))
    ERR1("Error: SDL: Mode",0ul);
  if ((k=DirList(view.dir,&buf,&l))==-1l)
    ERR1("Error: DirList",0ul);
  tmp=view.tmp; dir=view.dir; l=0;
  if (buf[l][0]=='.' && buf[l][1]==0) ++l;
  if (Load(dir,buf,l,tmp,&img,scr,ft)) return (-1);
  do
  { while (!SDL_PollEvent(&evt));
    switch (evt.type)
    { case SDL_MOUSEBUTTONUP:
        switch (evt.button.button)
        { case SDL_BUTTON_LEFT:
            butt&=~1; break;
          case SDL_BUTTON_RIGHT:
            butt&=~2; break;
          case SDL_BUTTON_MIDDLE:
            butt&=~4; break;
        }
        break;
      case SDL_MOUSEBUTTONDOWN:
        switch (evt.button.button)
        { case SDL_BUTTON_LEFT: butt|=1;
            evt.type=SDL_KEYUP;
            if (butt&4)
              evt.key.keysym.sym=SDLK_DOWN;
            else
              evt.key.keysym.sym=SDLK_RIGHT;
            break;
          case SDL_BUTTON_RIGHT: butt|=2;
            evt.type=SDL_KEYUP;
            if (butt&1)
              evt.key.keysym.sym=SDLK_DELETE;
            else
            if (butt&4)
              evt.key.keysym.sym=SDLK_UP;
            else
              evt.key.keysym.sym=SDLK_LEFT;
            break;
          case SDL_BUTTON_MIDDLE: butt|=4;
            break;
        }
        break;
    }
    switch (evt.type)
    { case SDL_KEYUP:
        switch (evt.key.keysym.sym)
        { case SDLK_ESCAPE:
            poll=0;
            break;
          case SDLK_RIGHT:
          case SDLK_SPACE:
            if (l<k-1)
            { ++l;
              if (buf[l][0]=='.' && buf[l][1]==0)
              { if (l<k) ++l; else --l; }
              if (Load(dir,buf,l,tmp,&img,scr,ft)) return (-1);
            }
            break;
          case SDLK_LEFT:
          case SDLK_BACKSPACE:
            if (l)
            { --l;
              if (buf[l][0]=='.' && buf[l][1]==0)
              { if (l) --l; else ++l; }
              if (Load(dir,buf,l,tmp,&img,scr,ft)) return (-1);
            }
            break;
          case SDLK_UP:
          case SDLK_DOWN:
          case SDLK_RETURN:
            if ((buf[l][0]=='.' && buf[l][1]=='.' && buf[l][2]==0) ||
                evt.key.keysym.sym==SDLK_UP)
            { p1=dir; i=j=StrLen(p1);
              for (--i;i && p1[i]!='/';--i);
              if (p1[i]=='/' && j>1)
              { if (i==0)
                { if (!(nam=MemGet(2)))
                    ERR1("Error: Nomem: Dir",0ul);
                  nam[0]='/'; nam[1]=0;
                } else
                { if (!(nam=MemGet(i)))
                    ERR1("Error: Nomem: Dir",0ul);
                  MemCpy(p1,nam,i); nam[i]=0;
                }
              } else break;
            } else
            { i=StrLen(dir); j=StrLen(buf[l]);
              if (!(nam=MemGet(i+j+2)))
                ERR1("Error: Nomem: Dir",0ul);
              MemCpy(dir,nam,i);
              MemCpy(buf[l],nam+i+1,j);
              nam[i]='/'; nam[i+1+j]=0;
            }
            MemRel(dir); dir=nam;
            MemRel(*buf); MemRel(buf);
            if ((k=DirList(dir,&buf,&l))==-1l)
              ERR1("Error: DirList",0ul); l=0;
            if (buf[l][0]=='.' && buf[l][1]==0) ++l;
            if (Load(dir,buf,l,tmp,&img,scr,ft)) return (-1);
            break;
          case SDLK_INSERT:
            if (Load(dir,buf,l,tmp,&img,scr,ft)) return (-1);
            break;
          case SDLK_DELETE:
            SDL_FillRect(scr,NULL,0);
            SDL_UpdateRect(scr,0,0,scr->w,scr->h);
            break;
          case SDLK_TAB:
            { SDL_Rect r1; int w,h;
              SDL_Color col={0x00,0xE0,0x00,0};
              SDL_Surface *txt;
              if (TTF_SizeText(ft,nam1,&w,&h))
                ERR1("Error: TTF: Size",0ul);
              if (!(txt=TTF_RenderText_Solid(ft,nam1,col)))
                ERR1("Error: TTF: Render",0ul);
              r1.x=0; r1.y=0; r1.w=w; r1.h=h;
              SDL_BlitSurface(txt,NULL,scr,&r1);
              r1.x=1; r1.y=0; r1.w=w; r1.h=h;
              SDL_BlitSurface(txt,NULL,scr,&r1);
              SDL_UpdateRect(scr,0,0,r1.w+1,r1.h);
            }
            break;
          default: break;
        }
        break;
      case SDL_QUIT:
        poll=0;
        break;
      case SDL_VIDEORESIZE:
        if (!(scr=SDL_SetVideoMode
          (evt.resize.w,evt.resize.h,32,
          SDL_SWSURFACE|SDL_RESIZABLE)))
          ERR1("Error: SDL: Mode",0ul);
        if (img)
        { r1.x=scr->w/2-img->w/2;
          r1.y=scr->h/2-img->h/2;
          SDL_BlitSurface(img,NULL,scr,&r1);
          SDL_UpdateRect(scr,0,0,scr->w,scr->h);
        }
        break;
    }
  } while (poll);
  MemRel(dir);
  MemRel(*buf); MemRel(buf);
  unlink(view.tmp);
  SDL_FreeSurface(img);
  TTF_CloseFont(ft);
  TTF_Quit();
  SDL_Quit();

  return (0);
}

I4 DirList(Str nam,Str **buf,N4 *len)
{ DIR *dir; struct dirent *ent;
  N4 i,j,k,l; Str *dd,p0,p1,p2;
  if (buf) *buf=NULL;
  if (len) *len=0;
  if (!buf) return (-1l);

  if (!(dir=opendir(nam))) return (-1l);
  for (k=0,l=0;(ent=readdir(dir));
    l+=StrLen(ent->d_name)+1,++k);
  if (!(p0=MemGet(l)))
  { closedir(dir); return (-1l); }
  if (!(dd=MemGet(k*sizeof(Str))))
  { closedir(dir); return (-1l); }
  rewinddir(dir);
  for (i=0,p1=p0;(ent=readdir(dir)) && i<k;++i)
  { p2=ent->d_name; j=StrLen(p2);
    if (p1-p0+j+1>l) { i=-1l; break; }
    MemCpy(p2,p1,j); p1[j]=0;
    dd[i]=p1; p1+=j+1;
  }
  closedir(dir);
  if (i!=k)
  { MemRel(dd);
    MemRel(p0);
    return (-1l);
  }
  if (len) *len=l;
  *buf=dd;

  return (k);
}

I4 Load(Str dir,Str *buf,N4 pos,Str tmp,
  SDL_Surface **img,SDL_Surface *scr,TTF_Font *ft)
{ FILE *f1,*f2; N1 ms; N4 i,j,k;
  SDL_Rect r1; tJpeg2 jpg; int w,h;
  SDL_Color col={0xFF,0xFF,0xFF,0};
  SDL_Surface *txt; N1 ld=0;

  SDL_FillRect(scr,NULL,0);
  SDL_UpdateRect(scr,0,0,scr->w,scr->h);
  k=(i=StrLen(dir))+(j=StrLen(buf[pos]))+2;
  if (nam1) MemRel(nam1);
  if (!(nam1=MemGet(k)))
    ERR1("Error: Nomem: File",0ul);
  MemCpy(dir,nam1,i);
  MemCpy(buf[pos],nam1+i+1,j);
  nam1[i]='/'; nam1[i+1+j]=0;

  if ((f1=fopen(nam1,"rb"))!=NULL)
  { if ((f2=fopen(tmp,"wb"))==NULL)
      ERR1("Error: Open: Tmp",0ul);
    ms=prg->msg; prg->msg=1;
    jpeg2Beg(&jpg); i=jpeg2b(&jpg,f1,f2);
    jpeg2End(&jpg); prg->msg=ms;
    fclose(f2); fclose(f1);
    if (!i)
    { //if (*img) SDL_FreeSurface(*img);
      if ((*img=SDL_LoadBMP(tmp)) && (ld=1))
      { r1.x=scr->w/2-(*img)->w/2;
        r1.y=scr->h/2-(*img)->h/2;
        SDL_BlitSurface(*img,NULL,scr,&r1);
        SDL_UpdateRect(scr,0,0,scr->w,scr->h);
      } else WARN2("Warn: Read: '%s'",0ul,nam1);
    } else WARN2("Warn: Jpeg: '%s'",0ul,nam1);
  }
  if (!ld)
  { if (TTF_SizeText(ft,nam1,&w,&h))
      ERR1("Error: TTF: Size",0ul);
    if (!(txt=TTF_RenderText_Solid(ft,nam1,col)))
      ERR1("Error: TTF: Render",0ul);
    r1.x=r1.y=0; r1.w=w; r1.h=h;
    SDL_BlitSurface(txt,NULL,scr,&r1);
    SDL_UpdateRect(scr,0,0,r1.w,r1.h);
  }
  return (0);
}


#endif
